﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.SharePoint.Administration;
using System.Collections.ObjectModel;
using Microsoft.SharePoint;

namespace SPALM
{
    internal class AddAndDeploySandboxedSolutionsOperation : DeploymentOperation
    {
        private string Solutions;
        private string SiteCollections;
        private bool Overwrite;     

        private string[] solutionNames;
        private string[] solutionFileNames;
        private string[] siteCollectionNames;

        public AddAndDeploySandboxedSolutionsOperation(Deployment parentTask, string Solutions, string SiteCollections, bool ParsedOverwrite, int ParsedRetries, int ParsedWaitSecondsAfterFinish, bool ParsedSimulateDeployment)
        : base(parentTask, ParsedRetries, ParsedWaitSecondsAfterFinish, ParsedSimulateDeployment)
        {            
            // TODO: Complete member initialization
            this.Solutions = Solutions;
            this.SiteCollections = SiteCollections;
            this.Overwrite = ParsedOverwrite;
            
            //Parameter extraction
            solutionNames = GetSolutionNames(Solutions);
            solutionFileNames = GetArrayFromString(Solutions);
            siteCollectionNames = GetArrayFromString(SiteCollections);
        }

        public override void CheckPreconditions()
        {
            LogMessage(FormatHeader("Check preconditions"), LogLevel.High);
            
            //1. Checks
            if(solutionFileNames.Length == 0)            
            {
                exceptions.Add("No solutions given in parameter 'Solutions'");
            }

            //1. Checks
            if (siteCollectionNames.Length == 0)
            {
                exceptions.Add("No site collections given in parameter 'Sites'");
            }

            //a. Existieren alle übergeben Dateien
            LogMessage("Check existence of wsp files...", LogLevel.Normal);  
            foreach (string solutionFileName in solutionFileNames)
            {
                LogMessage("Checking solution '" + solutionFileName + "'", LogLevel.Low);
                if (!File.Exists(solutionFileName))
                {
                    exceptions.Add("Solution '" + solutionFileName + "' not found.");
                }
            }

            //Existieren die angegebenen Sites
            if (siteCollectionNames.Length > 0)
            {
                LogMessage("Check existing site collections...", LogLevel.Normal);
                foreach (string siteCollectionName in siteCollectionNames)
                {
                    LogMessage("Checking site collection '" + siteCollectionName + "'", LogLevel.Low);
                    if (!SiteCollectionExistsOnServer(siteCollectionName))
                    {
                        exceptions.Add("Site collection '" + siteCollectionName + "' does not exists on server.");
                    }
                }
            }

            //b. Existieren die Lösungen bereits auf dem Server
            if (!Overwrite)
            {
                LogMessage("Check for existing solutions in sites...", LogLevel.Normal);
                foreach (string solutionName in solutionNames)
                {
                    foreach (string siteCollectionName in siteCollectionNames)
                    {
                        LogMessage("Checking '" + solutionName + "' in site '" + siteCollectionName + "'", LogLevel.Low);
                        if (SolutionExistsInSiteCollection(solutionName, siteCollectionName) && !Overwrite)
                        {
                            exceptions.Add("Solution '" + solutionName + "' already exists on server but task parameter 'Overwrite' is not true.");
                        }
                    }
                }
            }

            //ist eine content DB readonly
            LogMessage("Check if content database is readonly...", LogLevel.Normal);
            foreach (string siteCollectionName in siteCollectionNames)
            {
              using (SPSite site = new SPSite(siteCollectionName))
              {
                if (site != null)
                {
                  if (site.ContentDatabase.IsReadOnly)
                  {
                    exceptions.Add("Content database of site '" + siteCollectionName + "' is read-only.");
                  }
                }
              }
            }

            HandleExceptions();

            LogMessage(FormatHeader("Check preconditions finished successfully"), LogLevel.High);
            LogMessage("", LogLevel.High);
        }
                
        public override void PrepareSystem()
        {
            LogMessage(FormatHeader("Prepare system"), LogLevel.High);

            foreach (string solutionName in solutionNames)
            {
                foreach (string siteCollectionName in siteCollectionNames)
                {
                    LogMessage("Checking '" + solutionName + "' in site '" + siteCollectionName + "'...", LogLevel.Normal);
                    if (SolutionExistsInSiteCollection(solutionName, siteCollectionName))
                    {
                        DeleteSandBoxedSolution(solutionName, siteCollectionName);
                    }
                }
            }
            LogMessage(FormatHeader("Prepare system finished successfully"), LogLevel.High);
            LogMessage("", LogLevel.High);
        }

        private void DeleteSandBoxedSolution(string solutionName, string siteCollectionName)
        {

          using (SPSite site = new SPSite(siteCollectionName))
          {

            //deactivating sbs solution
            try
            {
              //finde die solution und deaktiviere                                
              foreach (SPUserSolution userSolution in site.Solutions)
              {
                if (userSolution.Name.Equals(solutionName, StringComparison.InvariantCultureIgnoreCase))
                {
                  LogMessage("Deactivating '" + solutionName + "' in site '" + siteCollectionName + "'...", LogLevel.Normal);
                  site.Solutions.Remove(userSolution);
                  break;
                }
              }
            }
            catch (Exception ex)
            {
              exceptions.Add("Could not activate sandboxed solution '" + solutionName + "' in site '" + siteCollectionName + "' (" + ex.Message + ")");
            }
     
            LogMessage("Deleting '" + solutionName + "' in site '" + siteCollectionName + "'...", LogLevel.Normal);
            try
            {               
                SPList catalog = site.RootWeb.GetCatalog(SPListTemplateType.SolutionCatalog);
                string str = catalog.RootFolder.Url + "/" + Path.GetFileName(solutionName);
                catalog.RootFolder.Files[str].Delete();
                LogMessage("Deleted solution '" + solutionName + "' in site '" + siteCollectionName + "'", LogLevel.Low);
            }
            catch
            {
                exceptions.Add("Could not delete solution '" + solutionName + "' in site '" + siteCollectionName + "'");
            }
          }
        }

        public override void RunOperation()
        {
            LogMessage(FormatHeader("Adding sandboxed solutions to site collections"), LogLevel.High);            
            foreach (string siteCollectionName in siteCollectionNames)
            {
              using (SPSite site = new SPSite(siteCollectionName))
              {
                if (site != null)
                {
                  foreach (string solutionFileName in solutionFileNames)
                  {
                    LogMessage("Adding '" + Path.GetFileName(solutionFileName) + "' to '" + siteCollectionName + "'...", LogLevel.Normal);

                    FileStream stream = null;
                    try
                    {

                      SPList catalog = site.RootWeb.GetCatalog(SPListTemplateType.SolutionCatalog);
                      stream = new FileStream(solutionFileName, FileMode.Open, FileAccess.Read);
                      string str = catalog.RootFolder.Url + "/" + Path.GetFileName(solutionFileName);
                      catalog.RootFolder.Files.Add(str, stream, false);

                    }
                    catch (Exception ex)
                    {
                      exceptions.Add("Could not add solution '" + Path.GetFileName(solutionFileName) + "' to site '" + siteCollectionName + " (" + ex.Message + ")");
                    }
                    finally
                    {
                      if (stream != null)
                      {
                        try
                        {
                          stream.Close();
                        }
                        catch { }
                      }
                    }
                  }
                }
              }
            }           
            HandleExceptions();
            LogMessage(FormatHeader("Adding solutions finished successfully"), LogLevel.High);
            LogMessage("", LogLevel.High);
           
            LogMessage(FormatHeader("Activating sandboxed solutions in sites"), LogLevel.High);
            foreach (string siteCollectionName in siteCollectionNames)
            {
                using(SPSite site = new SPSite(siteCollectionName))
                {
                  if (site != null)
                  {
                    foreach (string solutionFileName in solutionFileNames)
                    {
                      LogMessage("Activating '" + Path.GetFileName(solutionFileName) + "' in '" + siteCollectionName + "'...", LogLevel.Normal);
                      try
                      {
                        SPList catalog = site.RootWeb.GetCatalog(SPListTemplateType.SolutionCatalog);
                        string str = catalog.RootFolder.Url + "/" + Path.GetFileName(solutionFileName);
                        int solutionGalleryId = catalog.RootFolder.Files[str].Item.ID;
                        site.Solutions.Add(solutionGalleryId);
                      }
                      catch (Exception ex)
                      {
                        exceptions.Add("Could not activate sandboxed solution '" + Path.GetFileName(solutionFileName) + "' in site '" + siteCollectionName + "' (" + ex.Message + ")");
                      }
                    }
                  }
                }
            }
            LogMessage(FormatHeader("Activating sandboxed solutions in sites finished successfully"), LogLevel.High);
            LogMessage("", LogLevel.High);
        }
                
        public override void ValidateSystem()
        {
            // TODO: Check that all solutions are deployed
        }
    }
}
